package com.chenjiaru.thread.startthread;

import com.chenjiaru.thread.util.ThreadUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;
import java.util.stream.IntStream;

/**
 *
 *  创建线程方式四：使用线程池
 * 一、线程池：
 *      线程池他类似数据库的连接池，预先准备好线程，等待分配任务，执行完任务释放到线程池中
 *      等待下次分配任务，这样就减少了频繁的创建销毁线程，在高并发的应用中性能提升更加明细
 *      他提供了一个线程队列，队列中保存着所有等待状态的线程。避免了创建与销毁额外开销，提高了响应的速度。
 *      统一管理线程，线程复用
 *
 * 二、线程池的体系结构：
 * 	java.util.concurrent.Executor : 负责线程的使用与调度的根接口
 * 		|--**ExecutorService 子接口: 线程池的主要接口
 * 			|--ThreadPoolExecutor 线程池的实现类
 * 			|--ScheduledExecutorService 子接口：负责线程的调度
 * 				|--ScheduledThreadPoolExecutor ：继承 ThreadPoolExecutor， 实现 ScheduledExecutorService
 *
 * 三、工具类 : Executors
 *      ExecutorService newFixedThreadPool() : 创建固定大小的线程池
 *      ExecutorService newCachedThreadPool() : 缓存线程池，线程池的数量不固定，可以根据需求自动的更改数量。
 *      ExecutorService newSingleThreadExecutor() : 创建单个线程池。线程池中只有一个线程
 *      ScheduledExecutorService newScheduledThreadPool() : 创建固定大小的线程，可以延迟或定时的执行任务。
 */
@Slf4j
public class ExecutorDemo {


    public static void main(String[] arr) {

        awaitTerminationTimeout();
    }

    /**
     * 1加到1000的和
     */
    private static void executorService() {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        List<Future<Integer>> futures = new ArrayList();
        IntStream.range(1, 11).forEach((i) -> {
            Future<Integer> future = executorService.submit(() -> {
                int sum = 0;
                try {
                    int start = (i - 1) * 100 + 1;
                    int end = i * 100 + 1;
                    Thread.currentThread().setName(start + "->" + end);
                    sum = IntStream.range(start, end).sum();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                log.info("sum={}", sum);
                return sum;
            });
            futures.add(future);
        });

        Integer num = 0;
        try {
            for (Future<Integer> future : futures) {
                num += future.get();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            executorService.shutdownNow();
        }
        log.info("1加到1000的和={}", num);
    }


    /**
     * 线程执行超时处理
     */
    private static void getTimeout() {
        ExecutorService executorService = Executors.newFixedThreadPool(6);
        Future<Integer> future = executorService.submit(() -> {
            log.info("子线程开始执行");
            int sum = 0;
            try {
                Thread.sleep(2000);
                sum = IntStream.range(1, 1001).sum();
            } catch (Exception e) {
                log.error(e.getMessage());
            }
            return sum;
        });

        log.info("程阻塞等待子线程的计算");
        Integer num = 0;
        try {
            num += future.get(1, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("阻塞超时，中断子线程...");
            future.cancel(true);
        } finally {
            executorService.shutdown();
        }
        log.info("1加到1000的和={}", num);
    }


    /**
     * 线程池执行超时处理
     */
    private static void awaitTerminationTimeout() {
        ExecutorService executorService = Executors.newFixedThreadPool(4);
        List<Future<Integer>> futures = new ArrayList();
        IntStream.range(1, 5).forEach((i) -> {
            Future<Integer> future = executorService.submit(() -> {
                int start = (i - 1) * 100 + 1;
                int end = i * 100 + 1;
                Thread.currentThread().setName(start + "->" + end);
                log.info("开始执行...");
                int sum = 0;
                try {
                    Thread.sleep(2000);
                    sum = IntStream.range(start, end).sum();
                } catch (Exception e) {
                    log.error(e.getMessage());
                }
                log.info("执行完毕，sum={}", sum);
                return sum;
            });
            futures.add(future);
        });

        // 先发起关闭线程池命令（但是会等待所有任务执行完毕，才会关闭。）
        executorService.shutdown();
        Integer num = 0;
        try {
            if (executorService.awaitTermination(10, TimeUnit.SECONDS)) {
                for (Future<Integer> future : futures) {
                    num += future.get();
                }
                log.info("线程池按时完成任务，结果={}", num);
            } else {
                log.error("线程池执行超时...");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 这个会强制关闭线程池，并且给正在运行的线程发起中断信号
            executorService.shutdownNow();
        }
    }

}
